D:\a\scloud-dns\scloud-dns\src\dns\packet\header\mod.rs
Line | Count | Source |
1 | | use crate::exceptions::SCloudException; |
2 | | |
3 | | #[derive(Debug, PartialEq, Default)] |
4 | | pub struct Header { |
5 | | pub id: u16, // identifier |
6 | | pub qr: bool, // 0 for query, 1 for response |
7 | | pub opcode: u8, // 0 for standard query |
8 | | pub aa: bool, // authoritative answer |
9 | | pub tc: bool, // truncated message |
10 | | pub rd: bool, // recursion desired |
11 | | pub ra: bool, // recursion available |
12 | | pub z: u8, // reserved for future use |
13 | | pub rcode: u8, // 0 for no error |
14 | | pub qdcount: u16, // number of entries in the question section |
15 | | pub ancount: u16, // number of resource records in the answer section |
16 | | pub nscount: u16, // number of name server resource records in the authority records section |
17 | | pub arcount: u16, // number of resource records in the additional records section |
18 | | } |
19 | | |
20 | | impl Header { |
21 | | pub(crate) const DNS_HEADER_LEN: usize = 12; |
22 | | |
23 | | /// Serialize the DNS header into a byte array |
24 | | /// |
25 | | /// # Exemple : |
26 | | /// ``` |
27 | | /// use crate::dns::packet::header::Header; |
28 | | /// |
29 | | /// let header = Header { |
30 | | /// id: 0x1234, |
31 | | /// qr: false, |
32 | | /// opcode: 0, |
33 | | /// aa: false, |
34 | | /// tc: false, |
35 | | /// rd: true, |
36 | | /// ra: false, |
37 | | /// z: 0, |
38 | | /// rcode: 0, |
39 | | /// qdcount: 1, |
40 | | /// ancount: 0, |
41 | | /// nscount: 0, |
42 | | /// arcount: 0, |
43 | | /// }; |
44 | | /// |
45 | | /// let bytes = header.to_bytes().unwrap(); |
46 | | /// |
47 | | /// assert_eq!(bytes.len(), Header::DNS_HEADER_LEN); |
48 | | /// assert_eq!(bytes[0], 0x12); |
49 | | /// assert_eq!(bytes[1], 0x34); |
50 | | /// ``` |
51 | 5 | pub fn to_bytes(&self) -> Result<[u8; Self::DNS_HEADER_LEN], SCloudException> { |
52 | 5 | let mut bytes = [0u8; Self::DNS_HEADER_LEN]; |
53 | | |
54 | 5 | let id_bytes = self.id.to_be_bytes(); |
55 | 5 | bytes[0] = id_bytes[0]; |
56 | 5 | bytes[1] = id_bytes[1]; |
57 | | |
58 | 5 | let mut flags1 = 0u8; |
59 | 5 | flags1 |= (self.qr as u8 & 0x1) << 7; |
60 | 5 | flags1 |= (self.opcode & 0xF) << 3; |
61 | 5 | flags1 |= (self.aa as u8 & 0x1) << 2; |
62 | 5 | flags1 |= (self.tc as u8 & 0x1) << 1; |
63 | 5 | flags1 |= self.rd as u8 & 0x1; |
64 | | |
65 | 5 | let mut flags2 = 0u8; |
66 | 5 | flags2 |= (self.ra as u8 & 0x1) << 7; |
67 | 5 | flags2 |= (self.z & 0x7) << 4; |
68 | | |
69 | 5 | bytes[2] = flags1; |
70 | 5 | bytes[3] = flags2; |
71 | | |
72 | 5 | let qdcount_bytes = self.qdcount.to_be_bytes(); |
73 | 5 | bytes[4] = qdcount_bytes[0]; |
74 | 5 | bytes[5] = qdcount_bytes[1]; |
75 | | |
76 | 5 | let ancount_bytes = self.ancount.to_be_bytes(); |
77 | 5 | bytes[6] = ancount_bytes[0]; |
78 | 5 | bytes[7] = ancount_bytes[1]; |
79 | | |
80 | 5 | let nscount_bytes = self.nscount.to_be_bytes(); |
81 | 5 | bytes[8] = nscount_bytes[0]; |
82 | 5 | bytes[9] = nscount_bytes[1]; |
83 | | |
84 | 5 | let arcount_bytes = self.arcount.to_be_bytes(); |
85 | 5 | bytes[10] = arcount_bytes[0]; |
86 | 5 | bytes[11] = arcount_bytes[1]; |
87 | | |
88 | 5 | Ok(bytes) |
89 | 5 | } |
90 | | |
91 | | /// Deserialize the DNS header from a byte array |
92 | | /// |
93 | | /// # Exemple : |
94 | | /// ``` |
95 | | /// use crate::dns::packet::header::Header; |
96 | | /// |
97 | | /// let raw_header: [u8; 12] = [ |
98 | | /// 0x12, 0x34, // ID |
99 | | /// 0x01, 0x00, // Flags (standard query, RD = 1) |
100 | | /// 0x00, 0x01, // QDCOUNT = 1 |
101 | | /// 0x00, 0x00, // ANCOUNT = 0 |
102 | | /// 0x00, 0x00, // NSCOUNT = 0 |
103 | | /// 0x00, 0x00, // ARCOUNT = 0 |
104 | | /// ]; |
105 | | /// |
106 | | /// let header = Header::from_bytes(&raw_header).unwrap(); |
107 | | /// |
108 | | /// assert_eq!(header.id, 0x1234); |
109 | | /// assert_eq!(header.qr, false); |
110 | | /// assert_eq!(header.rd, true); |
111 | | /// assert_eq!(header.qdcount, 1); |
112 | | /// ``` |
113 | 4 | pub fn from_bytes(buf: &[u8]) -> Result<Header, SCloudException> { |
114 | 4 | if buf.len() == 0 { |
115 | 1 | return Err(SCloudException::SCLOUD_HEADER_BYTES_EMPTY); |
116 | 3 | } |
117 | | |
118 | 3 | if buf.len() < Header::DNS_HEADER_LEN { |
119 | 1 | return Err(SCloudException::SCLOUD_HEADER_DESERIALIZATION_FAILED); |
120 | 2 | } |
121 | | |
122 | 2 | Ok(Header { |
123 | 2 | id: u16::from_be_bytes([buf[0], buf[1]]), |
124 | 2 | qr: (buf[2] & 0b1000_0000) != 0, |
125 | 2 | opcode: (buf[2] & 0b0111_1000) >> 3, |
126 | 2 | aa: (buf[2] & 0b0000_0100) != 0, |
127 | 2 | tc: (buf[2] & 0b0000_0010) != 0, |
128 | 2 | rd: (buf[2] & 0b0000_0001) != 0, |
129 | 2 | ra: (buf[3] & 0b1000_0000) != 0, |
130 | 2 | z: (buf[3] & 0b0111_0000) >> 4, |
131 | 2 | rcode: buf[3] & 0b0000_1111, |
132 | 2 | qdcount: u16::from_be_bytes([buf[4], buf[5]]), |
133 | 2 | ancount: u16::from_be_bytes([buf[6], buf[7]]), |
134 | 2 | nscount: u16::from_be_bytes([buf[8], buf[9]]), |
135 | 2 | arcount: u16::from_be_bytes([buf[10], buf[11]]), |
136 | 2 | }) |
137 | 4 | } |
138 | | } |